package com.bjx.generator.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.bjx.api.system.constant.DictConst;
import com.bjx.api.system.domain.vo.DictDataVO;
import com.bjx.api.system.util.DictService;
import com.bjx.common.core.constant.FrameConst;
import com.bjx.common.core.exception.BJXException;
import com.bjx.common.core.util.DownloadUtil;
import com.bjx.generator.domain.entity.TableFieldEntity;
import com.bjx.generator.domain.entity.TemplateEntity;
import com.bjx.generator.domain.query.CreateCodeQuery;
import com.bjx.generator.domain.vo.TableInfoVO;
import com.bjx.generator.domain.vo.TableSonVO;
import com.bjx.generator.service.ICreateCodeService;
import com.bjx.generator.service.ITableInfoService;
import com.bjx.generator.service.ITemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.zip.ZipOutputStream;

/**
 * @desc: 生成代码业务
 * @author: liushuai
 * @date: 2022/9/22
 */
@Service
@Slf4j
public class CreateCodeServiceImpl implements ICreateCodeService {
    @Resource
    private ITemplateService templateService;
    @Resource
    private ITableInfoService tableInfoService;
    @Resource
    private DictService dictService;

    private static List<String> afterEndList = new ArrayList();
    static{
        afterEndList.add("java");
        afterEndList.add("xml");
    }

    @Override
    public void downloadCode(CreateCodeQuery createCodeQuery, HttpServletResponse response) {
        List<TemplateEntity> templateEntities = templateService.listTemplatesByTemplateIds(createCodeQuery.getTemplateIds());
        if(CollectionUtil.isEmpty(templateEntities)){
            throw new BJXException("模板不存在");
        }
        //java数据类型
        List<DictDataVO> dataTypes = dictService.listDictData(DictConst.DICT_DATA_TYPE);
        //筛选条件
        List<DictDataVO> screenCodeDict = dictService.listDictData(DictConst.DICT_SCREEN_CODE);

        TableInfoVO tableInfoVO = tableInfoService.selectTableInfoByTableId(createCodeQuery.getTableId());
        Dict params = setParams(tableInfoVO,dataTypes,screenCodeDict);
        //副表和子表
        List<TableSonVO> tableSons = tableInfoVO.getTableSons() == null? new ArrayList<TableSonVO>() : tableInfoVO.getTableSons();
        tableSons.forEach(item ->{
            TableInfoVO tableInfoVO1 = tableInfoService.selectTableInfoByTableId(item.getTableSubId());
            Dict sonParams = setParams(tableInfoVO1,dataTypes,screenCodeDict);
            params.set(item.getTemplateName(),sonParams);
        });
        ServletOutputStream outputStream = null;
        ZipOutputStream zipOutputStream = null;
        InputStream[] inputStreams = null;
        DownloadUtil.downloadZip(response,tableInfoVO.getTableName());
        try {
            outputStream = response.getOutputStream();
            //生成模板
            zipOutputStream = new ZipOutputStream(outputStream);
            inputStreams = new InputStream[templateEntities.size()];
            String[] paths = new String[templateEntities.size()];
            TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig());
            for (int i = 0; i < templateEntities.size(); i++) {
                TemplateEntity item = templateEntities.get(i);
                Template template = engine.getTemplate(item.getTemplateContent());
                String filePath = getFilePath(tableInfoVO,item.getFilePath(),engine);
                String packagePath = getPackagePath(tableInfoVO, filePath);
                params.set("packagePath",packagePath);
                String result = template.render(params);
                InputStream input = IoUtil.toStream(result,CharsetUtil.CHARSET_UTF_8);
                inputStreams[i] = input;
                String fileName =   getFileName(tableInfoVO,item.getFileName(),engine) + "."+item.getTemplateType();
                paths[i] = filePath + "/" + fileName;
            }
            ZipUtil.zip(zipOutputStream,paths,inputStreams);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
           IoUtil.close(outputStream);
           IoUtil.close(zipOutputStream);
           if(inputStreams != null){
               for(InputStream in : inputStreams) {
                   IoUtil.close(in);
               }
           }
        }
    }

    @Override
    public void createCode(CreateCodeQuery createCodeQuery) {
        List<TemplateEntity> templateEntities = templateService.listTemplatesByTemplateIds(createCodeQuery.getTemplateIds());
        if(CollectionUtil.isEmpty(templateEntities)){
            throw new BJXException("模板不存在");
        }
        TableInfoVO tableInfoVO = tableInfoService.selectTableInfoByTableId(createCodeQuery.getTableId());
        if(StrUtil.isEmpty(tableInfoVO.getAfterEndPath()) || StrUtil.isEmpty(tableInfoVO.getFrontEndPath())){
            throw new BJXException("前端或后端路径不能为空");
        }
        //java数据类型
        List<DictDataVO> dataTypes = dictService.listDictData(DictConst.DICT_DATA_TYPE);
        //筛选条件
        List<DictDataVO> screenCodeDict = dictService.listDictData(DictConst.DICT_SCREEN_CODE);
        //副表和子表
        List<TableSonVO> tableSons = tableInfoVO.getTableSons() == null? new ArrayList<TableSonVO>() : tableInfoVO.getTableSons();
        Dict params = setParams(tableInfoVO,dataTypes,screenCodeDict);
        tableSons.forEach(item ->{
            TableInfoVO tableInfoVO1 = tableInfoService.selectTableInfoByTableId(item.getTableSubId());
            Dict sonParams = setParams(tableInfoVO1,dataTypes,screenCodeDict);
            params.set(item.getTemplateName(),sonParams);
        });
        FileOutputStream outputStream = null;
        InputStream input = null;
        try {
            TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig());
            for (int i = 0; i < templateEntities.size(); i++) {
                TemplateEntity item = templateEntities.get(i);
                String filePath = getFilePath(tableInfoVO,item.getFilePath(),engine);
                String packagePath = getPackagePath(tableInfoVO,filePath);
                params.set("packagePath",packagePath);
                log.info("模板名称:{}",item.getTemplateName());
                Template template = engine.getTemplate(item.getTemplateContent());
                String result = template.render(params);
                input = IoUtil.toStream(result,CharsetUtil.CHARSET_UTF_8);
                String fileName =   getFileName(tableInfoVO,item.getFileName(),engine) + "."+item.getTemplateType();

                if(afterEndList.contains(item.getTemplateType())){
                    FileUtil.mkdirsSafely(new File(tableInfoVO.getAfterEndPath()+"/"+ filePath),5,500);
                    File file = FileUtil.file(tableInfoVO.getAfterEndPath()+"/"+ filePath + "/" + fileName);
                    outputStream = new FileOutputStream(file);
                    IoUtil.copy(input,outputStream);
                    IoUtil.close(outputStream);
                }else{
                    FileUtil.mkdirsSafely(new File(tableInfoVO.getFrontEndPath()+"/"+ filePath),5,500);
                    File file = FileUtil.file(tableInfoVO.getFrontEndPath()+"/"+ filePath + "/" + fileName);
                    outputStream = new FileOutputStream(file);
                    IoUtil.copy(input,outputStream);
                    IoUtil.close(outputStream);
                }

            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            IoUtil.close(input);
            IoUtil.close(outputStream);
        }
    }



    /**
     * 设置参数
     * @param tableInfoVO
     * @param dataTypes
     * @param screenCodeDict
     * @return: cn.hutool.core.lang.Dict
     * @Author: liushuai
     * @Date: 2022/9/23 14:25
     */
    public Dict setParams(TableInfoVO tableInfoVO,List<DictDataVO> dataTypes,List<DictDataVO> screenCodeDict){
        Dict params = Dict.create();
        //表名
        params.set("tableName",tableInfoVO.getTableName());
        //类名
        params.set("ClassName",tableInfoVO.getClassName());
        //类名小写
        params.set("className", StrUtil.lowerFirst(tableInfoVO.getClassName()));
        //描述名称
        params.set("descName",tableInfoVO.getDescName());
        //基础包路径
        params.set("basePackagePath",tableInfoVO.getPackagePath());
        //作者
        params.set("author",Optional.of(tableInfoVO.getAuthor()).orElse(""));
        //模块名称
        params.set("modelName",tableInfoVO.getModelName());
        //当前日期
        params.set("currentDate",DateUtil.format(new Date(),"yyyy/MM/dd"));
        //当前时间
        params.set("currentTime",DateUtil.format(new Date(),"yyyy/MM/dd HH:mm:ss"));
        //全字段
        List<TableFieldEntity> fields = tableInfoVO.getFields() == null? new ArrayList<TableFieldEntity>() : tableInfoVO.getFields();
        List<Dict> fieldDicts = new ArrayList<Dict>();
        fields.forEach(item ->{
            Dict dict = new Dict();
            dict.set("fieldName",item.getFieldName());
            dict.set("javaName",StrUtil.lowerFirst(StrUtil.toCamelCase(item.getFieldName())));
            dict.set("fieldDesc",item.getFieldDesc());
            dict.set("fieldLength",item.getFieldLength());
            dict.set("javaType", DictService.getDictLabel(dataTypes,String.valueOf(item.getFieldType())));
            dict.set("isPk",item.getPrimaryKey());
            if(FrameConst.YES.shortValue() == item.getPrimaryKey()){
                params.set("pk",StrUtil.lowerFirst(StrUtil.toCamelCase(item.getFieldName())));
                params.set("Pk",StrUtil.upperFirst(StrUtil.toCamelCase(item.getFieldName())));
            }
            dict.set("isEmpty",item.getEmptyKey());
            dict.set("isOnly",item.getOnlyKey());
            dict.set("isQuery",item.getQueryBol());
            dict.set("isList",item.getListBol());
            dict.set("isInsert",item.getInsertBol());
            dict.set("isUpdate",item.getUpdateBol());
            dict.set("screen", DictService.getDictLabel(screenCodeDict,String.valueOf(item.getScreen())));
            dict.set("componentType",item.getComponentType());
            dict.set("dictTypeCode",item.getDictTypeCode());
            fieldDicts.add(dict);
        });
        params.set("fields",fieldDicts);
        return params;
    }

    /**
     * 获取文件名称
     * @param tableInfoVO
     * @param templateFileName
     * @return: java.lang.String
     * @Author: liushuai
     * @Date: 2022/9/28 16:38
     */
    public String  getFileName(TableInfoVO tableInfoVO,String templateFileName,TemplateEngine engine){
        Dict params = Dict.create();
        //类名
        params.set("ClassName",tableInfoVO.getClassName());
        //类名小写
        params.set("className", StrUtil.lowerFirst(tableInfoVO.getClassName()));
        Template template = engine.getTemplate(templateFileName);
        return template.render(params);
    }
    /**
     * 获取文件路径
     * @param tableInfoVO
     * @param templateFilePath
     * @param engine
     * @return: java.lang.String
     * @Author: liushuai
     * @Date: 2022/9/28 16:43
     */
    public String  getFilePath(TableInfoVO tableInfoVO,String templateFilePath,TemplateEngine engine){
        templateFilePath = Optional.of(templateFilePath).orElse("") ;
        Dict params = Dict.create();
        String packagePath = Optional.of(tableInfoVO.getPackagePath()).orElse("").replaceAll("\\.","/");
        //basePath
        params.set("basePath", packagePath + "/");
        //resources
        params.set("resources", "resources");
        params.set("ClassName",tableInfoVO.getClassName());
        //类名小写
        params.set("className", StrUtil.lowerFirst(tableInfoVO.getClassName()));
        //模块名称
        params.set("modelName",tableInfoVO.getModelName());
        Template template = engine.getTemplate(templateFilePath);
        return template.render(params);
    }


    /**
     * 获取packagePath
     * @param tableInfoVO
     * @param filePath
     * @return: java.lang.String
     * @Author: liushuai
     * @Date: 2022/9/29 16:19
     */
    private String getPackagePath(TableInfoVO tableInfoVO, String filePath) {
        String packagePath = tableInfoVO.getPackagePath();
        filePath = filePath.replaceAll("/",".").replaceAll("\\.\\.",".");
        int index = filePath.indexOf(packagePath);
        if(index != -1){
            return filePath.substring(index);
        }else{
            return  filePath;
        }
    }

}
